/**
 * 可以参照：<https://www.luogu.com.cn/problem/P6801>，思路是相同的
 */

#include <cstdio>
using namespace std;
const int maxn = 1010;
int S[maxn][maxn], cumulative_height[maxn][maxn];
int stack_H[maxn], stack_W[maxn], stack_top, sum;
int n, m;
int main() {
  int T;
  scanf("%d", &T);
  while (T--) {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
      for (int j = 1; j <= m; ++j) {
        scanf("%d", &S[i][j]);
      }
    }
    for (int row = 1; row <= n; ++row)
      for (int col = 1; col <= m; ++col)
        cumulative_height[row][col] = (S[row][col] == S[row - 1][col]
                                           ? cumulative_height[row - 1][col] + 1
                                           : 1);
    long long ans = 0;
    for (int row = 1; row <= n; ++row) {
      stack_top = sum = 0;
      for (int col = 1; col <= m; ++col) {
        int h = cumulative_height[row][col], w = 1;
        // 与左一列数字不同，清空栈
        if (S[row][col] != S[row][col - 1]) sum = stack_top = 0;
        // 如果 stack_H 保持了单调性，不执行这个 while
        while (stack_top && h <= stack_H[stack_top]) {
          // stack_H 应该是单调递增的
          // 否则，从 sum 里去掉已经加进去的矩形，因为发现宽度可以拓展
          sum -= stack_H[stack_top] * stack_W[stack_top];
          w += stack_W[stack_top--];  // 拓展宽度
        }
        // 当前高度、宽度入栈
        stack_H[++stack_top] = h;  // 新的（被削平的）高度
        stack_W[stack_top] = w;    // 新的宽度
        // 增加如是多个矩形
        sum += stack_H[stack_top] * stack_W[stack_top];
        ans += sum;
      }
    }
    printf("%lld\n", ans);
  }
  return 0;
}
